<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Ubuntu使用心得">
<meta name="twitter:description" content="<p>安装包管理：dpkg命令，apt命令；Python：通过get-pip.py安装pip，升级python3的问题，site模块；我的WSL Ubuntu初始化操作；Docker：安装docker-ce，prtainer图形化管理工具</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/ubuntu-how-to-basic.html"/>
<meta property="og:title" content="来玩魔王的咚 | Ubuntu使用心得" />
<meta property="og:description" content="<p>安装包管理：dpkg命令，apt命令；Python：通过get-pip.py安装pip，升级python3的问题，site模块；我的WSL Ubuntu初始化操作；Docker：安装docker-ce，prtainer图形化管理工具</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>安装包管理：dpkg命令，apt命令；Python：通过get-pip.py安装pip，升级python3的问题，site模块；我的WSL Ubuntu初始化操作；Docker：安装docker-ce，prtainer图形化管理工具</p>" />

    <meta name="tags" content="WSL" />
    <meta name="tags" content="ubuntu" />
    <meta name="tags" content="python" />
    <meta name="tags" content="docker" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li class="active"><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-09-27 16:30:00+08:00">
                <script>document.write(moment('2020-09-27 16:30:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-09-27 16:30:00+08:00">
                <script>document.write(moment('2020-10-30 11:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Ubuntu使用心得
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#an-zhuang-bao-guan-li">安装包管理</a><ul>
<li><a href="#dpkg-ming-ling">dpkg命令</a></li>
<li><a href="#apt-ming-ling">apt命令</a></li>
</ul>
</li>
<li><a href="#python">Python</a><ul>
<li><a href="#shi-yong-python-ming-ling">使用python命令</a></li>
<li><a href="#an-zhuang-pip">安装pip</a></li>
<li><a href="#sheng-ji-python3-de-wen-ti">升级python3的问题</a></li>
<li><a href="#site-mo-kuai">site模块</a></li>
</ul>
</li>
<li><a href="#wo-de-wsl-ubuntu-chu-shi-hua-cao-zuo">我的WSL Ubuntu初始化操作</a></li>
<li><a href="#docker">Docker</a><ul>
<li><a href="#an-zhuang-docker-ce">安装docker-ce</a></li>
<li><a href="#docker-an-zhuang-hou-de-bu-zhou">docker安装后的步骤</a></li>
<li><a href="#prtainer-tu-xing-hua-guan-li-gong-ju">prtainer图形化管理工具</a></li>
</ul>
</li>
</ul>
</div>
<p>主要是在Windows的WSL中使用Ubuntu子系统。<br>
应用商店中的名称是：Ubuntu  </p>
<blockquote>
<p>This app installs the Ubuntu 20.04 LTS release on Windows.  </p>
</blockquote>
<p>命令行中查看版本信息：</p>
<div class="highlight"><pre><span></span><code>$ cat /etc/issue
Ubuntu <span class="m">20</span>.04.1 LTS <span class="se">\n</span> <span class="se">\l</span>
</code></pre></div>

<h3 id="an-zhuang-bao-guan-li"><a class="toclink" href="#an-zhuang-bao-guan-li">安装包管理</a></h3>
<p>Ubuntu系统有自己的包管理工具：apt，dpkg，tasksel，aptitude等。<br>
apt类似yum，dpkg类似rpm。  </p>
<h4 id="dpkg-ming-ling"><a class="toclink" href="#dpkg-ming-ling">dpkg命令</a></h4>
<p>dpkg常用命令：</p>
<ul>
<li>安装软件：dpkg -i </li>
<li>移除软件：dpkg -r </li>
<li>查看某个软件包是否已经安装：dpkg -l </li>
<li>查看某个软件包中都包含哪些文件：dpkg -L </li>
<li>查看系统中的某个文件是由哪个软件包提供的： dpkg -S /path/to/file</li>
<li>查看哪些软件包未完成安装：dpkg -C</li>
<li>重置软件配置文件 dpkg-reconfigure </li>
</ul>
<p>dpkg是底层的包管理工具，不太常用，最常用的是apt。  </p>
<h4 id="apt-ming-ling"><a class="toclink" href="#apt-ming-ling">apt命令</a></h4>
<p>系统有两套命令，旧的apt-get、apt-cache 和 apt-config，功能更多但是平时也用不到。<br>
新的apt命令，基本操作都用，并且更友好，而且就1个入口。设计的目的就是为了让普通用户更满意。  </p>
<h5 id="ming-ling-he-gong-neng"><a class="toclink" href="#ming-ling-he-gong-neng">命令和功能</a></h5>
<p>下面是新旧命令的对照参考：</p>
<table>
<thead>
<tr>
<th align="left">apt 命令</th>
<th align="left">取代的命令</th>
<th align="left">命令的功能</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">apt install</td>
<td align="left">apt-get install</td>
<td align="left">安装软件包</td>
</tr>
<tr>
<td align="left">apt remove</td>
<td align="left">apt-get remove</td>
<td align="left">移除软件包</td>
</tr>
<tr>
<td align="left">apt purge</td>
<td align="left">apt-get purge</td>
<td align="left">移除软件包及配置文件</td>
</tr>
<tr>
<td align="left">apt update</td>
<td align="left">apt-get update</td>
<td align="left">刷新存储库索引</td>
</tr>
<tr>
<td align="left">apt upgrade</td>
<td align="left">apt-get upgrade</td>
<td align="left">升级所有可升级的软件包</td>
</tr>
<tr>
<td align="left">apt autoremove</td>
<td align="left">apt-get autoremove</td>
<td align="left">自动删除不需要的包</td>
</tr>
<tr>
<td align="left">apt full-upgrade</td>
<td align="left">apt-get dist-upgrade</td>
<td align="left">在升级软件包时自动处理依赖关系</td>
</tr>
<tr>
<td align="left">apt search</td>
<td align="left">apt-cache search</td>
<td align="left">搜索应用程序</td>
</tr>
<tr>
<td align="left">apt show</td>
<td align="left">apt-cache show</td>
<td align="left">显示安装细节</td>
</tr>
<tr>
<td align="left">apt list</td>
<td align="left">无</td>
<td align="left">列出包含条件的包（已安装，可升级等）</td>
</tr>
<tr>
<td align="left">apt edit-sources</td>
<td align="left">无</td>
<td align="left">编辑源列表</td>
</tr>
</tbody>
</table>
<p>尽量使用apt命令，并且apt对普通用户来说也已经够用了。  </p>
<h5 id="ti-huan-ruan-jian-yuan"><a class="toclink" href="#ti-huan-ruan-jian-yuan">替换软件源</a></h5>
<p>使用下面的命令就可以替换为阿里源：</p>
<div class="highlight"><pre><span></span><code>sudo cp /etc/apt/sources.list<span class="o">{</span>,.bak<span class="o">}</span>
sudo sed -i <span class="s1">&#39;s|http://archive.ubuntu.com|https://mirrors.aliyun.com|&#39;</span> /etc/apt/sources.list
</code></pre></div>

<p>替换后更新：</p>
<div class="highlight"><pre><span></span><code>sudo apt update
</code></pre></div>

<h3 id="python"><a class="toclink" href="#python">Python</a></h3>
<p>系统默认就安装了python3:</p>
<div class="highlight"><pre><span></span><code>$ python3 -V
Python <span class="m">3</span>.8.2
</code></pre></div>

<h4 id="shi-yong-python-ming-ling"><a class="toclink" href="#shi-yong-python-ming-ling">使用python命令</a></h4>
<p>一个软连接就解决了，不过居然还有这么简单的包，那就用一下：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt install python-is-python3
$ dpkg -L python-is-python3
/.
/usr
/usr/bin
/usr/share
/usr/share/doc
/usr/share/doc/python-is-python3
/usr/share/doc/python-is-python3/changelog.gz
/usr/share/doc/python-is-python3/copyright
/usr/bin/python
$ ll /usr/bin/python
lrwxrwxrwx <span class="m">1</span> root root <span class="m">7</span> Apr <span class="m">15</span> <span class="m">18</span>:45 /usr/bin/python -&gt; python3*
$ 
</code></pre></div>

<h4 id="an-zhuang-pip"><a class="toclink" href="#an-zhuang-pip">安装pip</a></h4>
<p>可以直接使用apt安装：</p>
<div class="highlight"><pre><span></span><code>sudo apt install python3-pip
</code></pre></div>

<p>安装在/usr目录下，我想要安装到/usr/local目录下。没用直接用apt安装，用下面的<strong>通过get-pip.py安装</strong>。  </p>
<h5 id="she-zhi-pypi-yuan"><a class="toclink" href="#she-zhi-pypi-yuan">设置pypi源</a></h5>
<p>首先还是先切换到root账号：</p>
<div class="highlight"><pre><span></span><code>$ sudo su -
</code></pre></div>

<p>pypi源要设置在root账号下，安装的时候需要有root权限才能安装到系统目录中。否则普通用户只有用户家目录的权限，pip命令此时会自动选择安装到用户家目录下。当然也可以为普通用户也设置一份pypi源，因为程序总是会查找当前用户家目录下的设置。但是一般都是要使用sudo或者切换到root账号，因为要把包安装到系统目录，这两种情况都是查找root账号的pypi源。  </p>
<p>如果已经安装好了pip，可以直接用命令添加:</p>
<div class="highlight"><pre><span></span><code>$ pip3 config <span class="nb">set</span> global.index-url https://mirrors.aliyun.com/pypi/simple/
$ pip3 config <span class="nb">set</span> install.trusted-host mirrors.aliyun.com
</code></pre></div>

<p>使用上面的命令，写入的配置文件是~/.config/pip/pip.conf。  </p>
<p>还没安装pip的，可以直接写入配置文件。下面<strong>通过get-pip.py安装</strong>的时候，pypi源的设置也是有用的，安装过程中下载会快很多。<br>
设置使用阿里源，参考阿里源PyPi镜像的帮助，将配置写入~/.pip/pip.conf文件：</p>
<div class="highlight"><pre><span></span><code>mkdir ~/.pip
cat &gt; ~/.pip/pip.conf <span class="s">&lt;&lt; EOF</span>
<span class="s">[global]</span>
<span class="s">index-url = https://mirrors.aliyun.com/pypi/simple/</span>

<span class="s">[install]</span>
<span class="s">trusted-host = mirrors.aliyun.com</span>
<span class="s">EOF</span>
</code></pre></div>

<p>这里配置文件的位置与使用pip命令写入的文件的位置不一样，不过都是有效的。  </p>
<h5 id="tong-guo-get-pippy-an-zhuang"><a class="toclink" href="#tong-guo-get-pippy-an-zhuang">通过get-pip.py安装</a></h5>
<p>参考pypi的pip文档： <a href="https://pypi.org/project/pip/">https://pypi.org/project/pip/</a><br>
先把上一节的pip源设置好，这样执行脚本安装的时候是从国内镜像源获取资源，能快很多。先下载脚本，再执行脚本安装：</p>
<div class="highlight"><pre><span></span><code>sudo su -
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
</code></pre></div>

<p>直接运行就是安装，默认设置安装就可以了。<br>
使用-h可以查看帮助，用--prefix可以指定安装目录。不过默认就安装到/usr/locl下，已经符合我需要了。  </p>
<h5 id="she-zhi-bie-ming-bu-tui-jian"><a class="toclink" href="#she-zhi-bie-ming-bu-tui-jian">设置别名（不推荐）</a></h5>
<p><strong>不推荐的原因</strong><br>
这是我一开始的做法。后来发现由于sudo有自己的PATH设置，在使用虚拟环境venv的时候，就不能强制用sudo来调用pip了，sudo调用pip依然会去查找原来系统命令路径中的pip命令。推荐用下面的设置环境变量来解决。  </p>
<p>为普通用户增加一个别名设置：</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span> <span class="s2">&quot;alias pip3=&#39;sudo pip3&#39;&quot;</span> &gt;&gt; ~/.bash_aliases
<span class="nb">source</span> .bash_aliases
</code></pre></div>

<p>仅仅只用调用sudo而已。<br>
没有sudo权限也能执行pip，并且也不报错。但是会安装到用户目录下。所以执行的时候一定要加上sudo。这里的别名是为了防止忘记加sudo运行。  </p>
<p><strong>原因分析</strong><br>
调用sudo执行的pip，不仅仅只是获取了root权限，命令执行的用户也是root。所以模块是安装到系统的python目录中。另外，如果在用户家目录下设置了pypi源，此时认得是root用户家目录下的设置，而不是当前用户的家目录。如果是普通用户调用pip，其实并不会有系统文件夹权限的问题，而是直接就安装到了用户目录的某个位置。这些行为都是由site模块决定的，该模块就不在这篇里展开了。  </p>
<h5 id="she-zhi-huan-jing-bian-liang"><a class="toclink" href="#she-zhi-huan-jing-bian-liang">设置环境变量</a></h5>
<p>设置环境变量比上面的设置别名的方式更好。<br>
可以禁用ENABLE_USER_SITE来禁止使用用户目录。禁用后，安装和查找模块都不会无法选择使用用户目录。<br>
设置环境变量，禁用ENABLE_USER_SITE：</p>
<div class="highlight"><pre><span></span><code>$ echo &#39;export PYTHONNOUSERSITE=1&#39; &gt;&gt; ~/.profile
$ source .profile
$ python -m site
sys.path = [
    &#39;/home/steed&#39;,
    &#39;/usr/lib/python38.zip&#39;,
    &#39;/usr/lib/python3.8&#39;,
    &#39;/usr/lib/python3.8/lib-dynload&#39;,
    &#39;/usr/local/lib/python3.8/dist-packages&#39;,
    &#39;/usr/lib/python3/dist-packages&#39;,
]
USER_BASE: &#39;/home/steed/.local&#39; (doesn&#39;t exist)
USER_SITE: &#39;/home/steed/.local/lib/python3.8/site-packages&#39; (doesn&#39;t exist)
ENABLE_USER_SITE: False
$ 
</code></pre></div>

<p>这里确认到<code>ENABLE_USER_SITE: False</code>，表示设置生效了。<em>就不在这里对site模块展开了。</em>  </p>
<h5 id="sheng-ji-pip"><a class="toclink" href="#sheng-ji-pip">升级pip</a></h5>
<p>最好使用python启动，调用pip模块来升级：</p>
<div class="highlight"><pre><span></span><code>python3 -m pip install -U pip
</code></pre></div>

<p>用这个命令最稳，最安全。  </p>
<p>下面的命令也是一样的，但是Windows平台执行后不但无法升级，原来的pip也没了：</p>
<div class="highlight"><pre><span></span><code>$ pip install -U pip
</code></pre></div>

<p><em>推测是pip自身把自己删除后，再调用自己安装新版本导致的。上面用python调用，始终在python的进程中，直到升级完成才会退出。</em>  </p>
<h4 id="sheng-ji-python3-de-wen-ti"><a class="toclink" href="#sheng-ji-python3-de-wen-ti">升级python3的问题</a></h4>
<p>先说建议，原生的python3保留不要动，python3的软连接的指向也不要变（如果安装包改了，就再去改回来）。这样应该就保证不影响系统了。<br>
上面的建议只是避免折腾，保持系统原生的python3环境不变。不过如果能搞清楚问题的话，也是可以把问题逐个解决的。<em>难的是有些问题没有暴露出来就不知道，这就会是个隐患。</em>  </p>
<h5 id="an-zhuang-duo-ge-python-ban-ben"><a class="toclink" href="#an-zhuang-duo-ge-python-ban-ben">安装多个python版本</a></h5>
<p>要使用多个版本的python，则另外装一个，可以考虑编译安装。多个版本切换可以借助工具。<br>
用python自带的venv来切换python环境。主要是切换环境的，不同的环境安装的模块会不同。但是同时也是绑定python版本的，所以切换的时候版本也是一起切换的。<br>
另外还有个工具pyenv似乎更适合解决系统上多个python版本共存的问题，不过没用过。  </p>
<h5 id="xi-tong-zhong-shi-yong-de-python3"><a class="toclink" href="#xi-tong-zhong-shi-yong-de-python3">系统中使用的python3</a></h5>
<p>系统自带python3，并且一些系统命令也会调用python3。这里拿<code>/usr/lib/command-not-found</code>这个python程序举例，在执行系统没有的命令的时候，最后会调用这个程序。我们在界面上看到的那些系统提示就是这个程序打印出来的。<br>
这里也可以直接调用，后面跟1个参数（有且只能是1个），并且参数要命令，这个程序搜索的是命令名，搜不到还会模糊匹配：</p>
<div class="highlight"><pre><span></span><code>$ /usr/lib/command-not-found lrzsz
lrzsz: <span class="nb">command</span> not found
$ /usr/lib/command-not-found rz
The program <span class="s1">&#39;rz&#39;</span> is currently not installed. You can install it by typing:
apt install lrzsz
$  /usr/lib/command-not-found pyenv
No <span class="nb">command</span> <span class="s1">&#39;pyenv&#39;</span> found, did you mean:
 Command <span class="s1">&#39;p7env&#39;</span> from package <span class="s1">&#39;libnss3-tools&#39;</span> <span class="o">(</span>universe<span class="o">)</span>
 Command <span class="s1">&#39;pyvenv&#39;</span> from package <span class="s1">&#39;python3-venv&#39;</span> <span class="o">(</span>universe<span class="o">)</span>
pyenv: <span class="nb">command</span> not found
$ 
</code></pre></div>

<p>第一次，给了软件包的名字，当做命令去搜，没有搜到。<br>
第二次，给了命令名，搜到了对应的软件包。<br>
第三次，命令也是搜不到的，但是模糊匹配了另外两个差不多的。  </p>
<p>程序开头的部分代码如下：</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/python3</span>
<span class="c1"># (c) Zygmunt Krynicki 2005, 2006, 2007, 2008</span>
<span class="c1"># Licensed under GPL, see COPYING for the whole text</span>

<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">absolute_import</span><span class="p">,</span> <span class="n">print_function</span>


<span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;0.3&quot;</span>
<span class="n">BUG_REPORT_URL</span> <span class="o">=</span> <span class="s2">&quot;https://bugs.launchpad.net/command-not-found/+filebug&quot;</span>

<span class="k">try</span><span class="p">:</span>
    <span class="kn">import</span> <span class="nn">sys</span>
    <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="ow">and</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;/usr/lib&#39;</span><span class="p">:</span>
        <span class="c1"># Avoid ImportError noise due to odd installation location.</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version</span> <span class="o">&lt;</span> <span class="s1">&#39;3&#39;</span><span class="p">:</span>
        <span class="c1"># We might end up being executed with Python 2 due to an old</span>
        <span class="c1"># /etc/bash.bashrc.</span>
        <span class="kn">import</span> <span class="nn">os</span>
        <span class="k">if</span> <span class="s2">&quot;COMMAND_NOT_FOUND_FORCE_PYTHON2&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span>
            <span class="n">os</span><span class="o">.</span><span class="n">execvp</span><span class="p">(</span><span class="s2">&quot;/usr/bin/python3&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>

    <span class="kn">import</span> <span class="nn">gettext</span>
    <span class="kn">import</span> <span class="nn">locale</span>
    <span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span>

    <span class="kn">from</span> <span class="nn">CommandNotFound.util</span> <span class="kn">import</span> <span class="n">crash_guard</span>
    <span class="kn">from</span> <span class="nn">CommandNotFound</span> <span class="kn">import</span> <span class="n">CommandNotFound</span>
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
    <span class="kn">import</span> <span class="nn">sys</span>
    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">127</span><span class="p">)</span>
<span class="c1"># 后面还有代码，不贴了</span>
</code></pre></div>

<p>脚本调用的是<code>/usr/bin/python3</code>。所以这个链接尽量不要修改，就让它始终指向系统默认的python3命令。当然自己用的时候是会有一些小小的不便。<br>
这里还会导入CommandNotFound，模块可以在这里找到：</p>
<div class="highlight"><pre><span></span><code>$  find / -path /mnt -prune -o -type d -name CommandNotFound
/mnt
/usr/lib/python3/dist-packages/CommandNotFound
$ 
</code></pre></div>

<p>常见的问题就是报错<code>ImportError: No module named 'CommandNotFound'</code>。  </p>
<p>如果安装了其他的python3，并且替换了python3的软连接，那么系统脚本的调用也会被指向新的python3。此时新的python3的搜索路径没有包括之前安装的那些模块。<br>
知道了问题的原因，那么解决起来就有思路了。首先不推荐在新的版本中安装缺失的模块（并且也不一定有对应版本的软件包），复制一份去新的python3目录也一样不推荐。这些都是哪疼医哪的做法，下次可能还会报其他模块无法导入。<br>
这里只要解决python3程序的搜索路径，也就是sys.path，应该就可以了。推荐使用site模块来解决，具体看下一节。  </p>
<h4 id="site-mo-kuai"><a class="toclink" href="#site-mo-kuai">site模块</a></h4>
<p>python3的site模块： <a href="https://docs.python.org/zh-cn/3/library/site.html">https://docs.python.org/zh-cn/3/library/site.html</a><br>
只简单讲一下如何解决这里的问题。  </p>
<p>首先看一下当前python环境的目录位置：</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">site</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">site</span><span class="o">.</span><span class="n">getsitepackages</span><span class="p">()</span>
<span class="p">[</span><span class="s1">&#39;/usr/local/lib/python3.5/dist-packages&#39;</span><span class="p">,</span> <span class="s1">&#39;/usr/lib/python3.5/dist-packages&#39;</span><span class="p">]</span>
<span class="c1"># 这里实际输出是下面这样的，为了说明问题，假设少了一个路径</span>
<span class="c1"># [&#39;/usr/local/lib/python3.5/dist-packages&#39;, &#39;/usr/lib/python3/dist-packages&#39;, &#39;/usr/lib/python3.5/dist-packages&#39;]</span>
</code></pre></div>

<p>上面这个路径是由site.py程序决定的。  </p>
<p>可以找到上面这个文件好奇看一下：</p>
<div class="highlight"><pre><span></span><code>$ find / -path /mnt -prune -o -type f -name site.py -print
/usr/lib/python3.5/site.py
$ 
</code></pre></div>

<p>当然是不推荐去改源码的，模块也给普通用户留了其他安全的方式来添加路径。这里就先好奇了解一下，这几个目录是怎么决定的。  </p>
<p>在上面任意的一个目录下，创建文件名任意的.pth文件，也就是*.pth文件。在文件中以行为单位，写上需要追加导入的相对路径或绝对路径：</p>
<div class="highlight"><pre><span></span><code>$ cat /usr/local/lib/python3.5/dist-packages/python3.pth
/usr/lib/python3/dist-packages
</code></pre></div>

<p>这样新路径下的模块就可以被python程序找到了。<em>这里可以放心添加路径，不存在的项目不会添加到sys.path，并且也不会重复添加。</em>  </p>
<h3 id="wo-de-wsl-ubuntu-chu-shi-hua-cao-zuo"><a class="toclink" href="#wo-de-wsl-ubuntu-chu-shi-hua-cao-zuo">我的WSL Ubuntu初始化操作</a></h3>
<p>先登录root用户进行如下操作:</p>
<div class="highlight"><pre><span></span><code>sudo su -

rmdir /opt
<span class="c1"># P:\WSL\Ubuntu\opt 这个文件夹应该已经存在，并且有之前的项目目录</span>
ln -s /mnt/p/WSL/Ubuntu/opt /opt
<span class="c1"># P:\WSL\Ubuntu\usr 先把这个目录在Windows系统中删除</span>
mkdir /mnt/p/WSL/Ubuntu/usr
mv /usr/local /mnt/p/WSL/Ubuntu/usr/local
ln -s /mnt/p/WSL/Ubuntu/usr/local /usr/local

mkdir ~/.pip
cat &gt; ~/.pip/pip.conf <span class="s">&lt;&lt; EOF</span>
<span class="s">[global]</span>
<span class="s">index-url = https://mirrors.aliyun.com/pypi/simple/</span>

<span class="s">[install]</span>
<span class="s">trusted-host = mirrors.aliyun.com</span>
<span class="s">EOF</span>

<span class="nb">exit</span>
</code></pre></div>

<p>下面的操作在普通用户下继续操作：</p>
<div class="highlight"><pre><span></span><code>sudo cp /etc/apt/sources.list<span class="o">{</span>,.bak<span class="o">}</span>
sudo sed -i <span class="s1">&#39;s|http://archive.ubuntu.com|https://mirrors.aliyun.com|&#39;</span> /etc/apt/sources.list
sudo apt update

python --version <span class="o">||</span> sudo apt install python-is-python3

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo python get-pip.py
sudo python -m pip install -U pip
pip config <span class="nb">set</span> global.index-url https://mirrors.aliyun.com/pypi/simple/
pip config <span class="nb">set</span> install.trusted-host mirrors.aliyun.com

<span class="nb">echo</span> <span class="s2">&quot;alias findr=&#39;sudo find / /mnt/p/WSL/Ubuntu/ -path /mnt -prune -o&#39;&quot;</span> &gt;&gt; ~/.bash_aliases
<span class="nb">source</span> .bash_aliases
<span class="nb">echo</span> <span class="s1">&#39;export PYTHONNOUSERSITE=1&#39;</span> &gt;&gt; ~/.profile
<span class="nb">source</span> .profile

<span class="c1"># 如果要 GPG 密钥</span>
sudo apt remove gpg
sudo apt install gnupg1
</code></pre></div>

<h3 id="docker"><a class="toclink" href="#docker">Docker</a></h3>
<p>WSL不支持Docker的守护进程。所以能用的只有客户端（docker-ce-cli），也就是你还得另外在别处有一个Docker守护进程。<br>
可以在本机的Windows系统上装一个<strong>Docker for Windows</strong>，系统必须要开启Hyper-V（家庭版没有）。也可以是虚拟机或者远程的Linux服务器。<br>
<em>辛苦整理的安装过程，还是要留下安装记录的</em>。  </p>
<h4 id="an-zhuang-docker-ce"><a class="toclink" href="#an-zhuang-docker-ce">安装docker-ce</a></h4>
<p>docker官网 Install Docker Engine on Ubuntu : <a href="https://docs.docker.com/engine/install/ubuntu/">https://docs.docker.com/engine/install/ubuntu/</a>  </p>
<p>卸载旧版本：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get remove docker docker-engine docker.io containerd runc
</code></pre></div>

<p>没有安装旧版本也可以执行一下，不会有问题。  </p>
<p>安装依赖：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install <span class="se">\</span>
    apt-transport-https <span class="se">\</span>
    ca-certificates <span class="se">\</span>
    curl <span class="se">\</span>
    gnupg-agent <span class="se">\</span>
    software-properties-common
</code></pre></div>

<p>添加 Docker 官方的 GPG 密钥：</p>
<div class="highlight"><pre><span></span><code>$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
gpg: can&#39;t connect to the agent: IPC connect call failed
$ 
</code></pre></div>

<p>这里没成功，报错了。这个错误是WSL上的Ubuntu 20.04才有的。在微观github的WSL项目的Issues里有讨论（<a href="https://github.com/microsoft/WSL/issues/5125">https://github.com/microsoft/WSL/issues/5125</a>），里面也给出了解决办法。内容比较多，在页面里搜索“Best sollution”，可以找个一个推荐的办法。卸载有问题的gpg，安装个gnupg1来替代，具体如下：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt remove gpg
$ sudo apt install gnupg1
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg <span class="p">|</span> sudo apt-key add -
curl: <span class="o">(</span><span class="m">35</span><span class="o">)</span> OpenSSL SSL_connect: SSL_ERROR_SYSCALL <span class="k">in</span> connection to download.docker.com:443
gpg: no valid OpenPGP data found.
$ 
</code></pre></div>

<p>这里又报了个错，应该是国外资源网络原因。再试下就好了：</p>
<div class="highlight"><pre><span></span><code>$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg <span class="p">|</span> sudo apt-key add -
OK
$ 
</code></pre></div>

<p>这里有个阿里云的镜像地址：</p>
<div class="highlight"><pre><span></span><code>$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg <span class="p">|</span> sudo apt-key add -
OK
$ 
</code></pre></div>

<p>密钥（key）的数字签名（fingerprint）是<code>9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88</code>，搜索最后8个字符来确认一下：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-key fingerprint 0EBFCD88
pub   4096R/0EBFCD88 <span class="m">2017</span>-02-22
      Key <span class="nv">fingerprint</span> <span class="o">=</span> 9DC8 <span class="m">5822</span> 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release <span class="o">(</span>CE deb<span class="o">)</span> &lt;docker@docker.com&gt;
sub   4096R/F273FCD8 <span class="m">2017</span>-02-22

$ 
</code></pre></div>

<p>添加apt源：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt install software-properties-common
$ sudo add-apt-repository <span class="se">\</span>
   <span class="s2">&quot;deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \</span>
<span class="s2">   </span><span class="k">$(</span>lsb_release -cs<span class="k">)</span><span class="s2"> \</span>
<span class="s2">   stable&quot;</span>
</code></pre></div>

<p>默认没有add-apt-repository，先安装一下。<br>
官方源是<code>https://download.docker.com/linux/ubuntu</code>，这里就直接替换成阿里云的镜像了。  </p>
<p>列出镜像支持的版本：</p>
<div class="highlight"><pre><span></span><code>$ apt-cache madison docker-ce
 docker-ce <span class="p">|</span> <span class="m">5</span>:19.03.13~3-0~ubuntu-focal <span class="p">|</span> https://mirrors.aliyun.com/docker-ce/linux/ubuntu focal/stable amd64 Packages
 docker-ce <span class="p">|</span> <span class="m">5</span>:19.03.12~3-0~ubuntu-focal <span class="p">|</span> https://mirrors.aliyun.com/docker-ce/linux/ubuntu focal/stable amd64 Packages
 docker-ce <span class="p">|</span> <span class="m">5</span>:19.03.11~3-0~ubuntu-focal <span class="p">|</span> https://mirrors.aliyun.com/docker-ce/linux/ubuntu focal/stable amd64 Packages
 docker-ce <span class="p">|</span> <span class="m">5</span>:19.03.10~3-0~ubuntu-focal <span class="p">|</span> https://mirrors.aliyun.com/docker-ce/linux/ubuntu focal/stable amd64 Packages
 docker-ce <span class="p">|</span> <span class="m">5</span>:19.03.9~3-0~ubuntu-focal <span class="p">|</span> https://mirrors.aliyun.com/docker-ce/linux/ubuntu focal/stable amd64 Packages
$ 
</code></pre></div>

<p>第二列就是版本名称，比如<code>5:19.03.13~3-0~ubuntu-focal</code>。<br>
可以指定版本进行安装：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install docker-ce<span class="o">=</span>&lt;VERSION_STRING&gt; docker-ce-cli<span class="o">=</span>&lt;VERSION_STRING&gt; containerd.io
</code></pre></div>

<p>我这里安装默认的版本。  </p>
<p>更新源，然后安装：</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
</code></pre></div>

<p>在WSL上，可能就只需要装一个docker-ce-cli了。其它的安装也没问题，但是之后守护进程无法启动。  </p>
<p>查看版本信息：</p>
<div class="highlight"><pre><span></span><code>$ docker version
Client: Docker Engine - Community
 Version:           <span class="m">19</span>.03.13
 API version:       <span class="m">1</span>.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep <span class="m">16</span> <span class="m">17</span>:02:52 <span class="m">2020</span>
 OS/Arch:           linux/amd64
 Experimental:      <span class="nb">false</span>
Got permission denied <span class="k">while</span> trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version: dial unix /var/run/docker.sock: connect: permission denied
$ docker --version
Docker version <span class="m">19</span>.03.13, build 4484c46d9d
$ 
</code></pre></div>

<p>运行容器：</p>
<div class="highlight"><pre><span></span><code>$ sudo docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See <span class="s1">&#39;docker run --help&#39;</span>.
$ 
</code></pre></div>

<p>没有守护进程，到此结束了。  </p>
<h4 id="docker-an-zhuang-hou-de-bu-zhou"><a class="toclink" href="#docker-an-zhuang-hou-de-bu-zhou">docker安装后的步骤</a></h4>
<p>如果安装好了docker，还有以下的步骤需要操作，具体见官网 <a href="https://docs.docker.com/engine/install/linux-postinstall/">https://docs.docker.com/engine/install/linux-postinstall/</a> :</p>
<ol>
<li>设置非root用户使用</li>
<li>docker开启自启动</li>
<li>设置镜像加速器，使用国内镜像</li>
</ol>
<h4 id="prtainer-tu-xing-hua-guan-li-gong-ju"><a class="toclink" href="#prtainer-tu-xing-hua-guan-li-gong-ju">prtainer图形化管理工具</a></h4>
<p>启动镜像：</p>
<div class="highlight"><pre><span></span><code>$ docker run -d -p <span class="m">9000</span>:9000 --restart<span class="o">=</span>always -v /var/run/docker.sock:/var/run/docker.sock --name prtainer docker.io/portainer
</code></pre></div>

<p>启动后浏览器打开 http://localhost:9000/  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>